﻿// Operations and events related to showing or hiding an element using the display or the visibility CSS properties
define([
    'Wjs/Wjs'
],
function () {
    'use strict';

    return Wjs.defineOnce({

        type: 'Showable',

        internal: {

            listeners: {

                onDomElementCreated: function () {

                    if (this.hidden) { // If the element is initially hidden then hide it

                        this.hide();
                    }
                }

                // The hidden flag is not copied when cloned
            }
        },

        onBeforeShow: function (fcn) {

            this.beforeShowHandler = Wjs.chain(this.beforeShowHandler, fcn);

            return this;
        },

        onShow: function (fcn) {

            this.showHandler = Wjs.chain(this.showHandler, fcn);

            return this;
        },

        onHide: function (fcn) {

            this.hideHandler = Wjs.chain(this.hideHandler, fcn);

            return this;
        },

        // Sets the flag to use the visibility to hidden instead of the display to none
        // The reason for doing this is that elements with hidden visibility are still measurables (can retrieve their dimensions)
        // whereas elements with display set to none are not
        setUseVisibility: function (flag) {

            this.useVisibility = Wjs.isDefined(flag) ? flag : true;

            return this;
        },

        show: function (flag) {

            if (flag === false) {

                return this.hide();
            }

            if (!this.hidden) { // Already shown

                return this;
            }

            if (this.beforeShowHandler && this.beforeShowHandler() === false) {

                return this; // Cancel showing the component
            }

            this.hidden = false;

            if (this.isRendered()) { // Show it in the DOM

                if (this.useVisibility) {

                    this.domEl.style.visibility = 'visible';
                }
                else {

                    this.domEl.style.display = '';
                }
            }

            // Notify the mixins interested in handling this event
            this.constructor.notifyMixins('onElementVisible', this);

            if (this.showHandler) {

                this.showHandler();
            }

            // Notify the children that are not hidden of the show event
            this.down(function (item) {

                return !item.hidden;
            })
            .forEach(function (item) {

                if (item.showHandler) {

                    item.showHandler();
                }
            });

            return this;
        },

        hide: function (flag) {

            if (flag === false) {

                return this.show();
            }

            if (this.isRendered()) {

                if (this.useVisibility) {

                    this.domEl.style.visibility = 'hidden';
                }
                else {

                    this.domEl.style.display = 'none';
                }
            }

            this.hidden = true;

            // Notify the mixins interested in handling this event
            this.constructor.notifyMixins('onElementHidden', this);

            if (this.hideHandler) {

                this.hideHandler();
            }

            return this;
        },

        isHidden: function () {

            return this.hidden == true;
        }

    });
});